﻿using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Collections;

namespace AWSS3ToAzureBlob.Test
{
    /// <summary>
    /// Summary description for FileMigratorUnitTest
    /// </summary>
    [TestClass]
    public class FileMigratorUnitTest
    {
        public FileMigratorUnitTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        //private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        //public TestContext TestContext
        //{
        //    get
        //    {
        //        return testContextInstance;
        //    }
        //    set
        //    {
        //        testContextInstance = value;
        //    }
        //}

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        private Mock<IAWSS3Facade> _awsS3Mock = null;
        private Mock<IAzureStorageBlobFacade> _azureStorageBlobMock = null;
        private string _awsS3Bucket = "Bucket";
        private string _awsS3Account = "S3 Account";
        private string _awsS3Key = "S3 Key";
        private int _awsExpiryMinutes = 60;
        private string _azureStorageAccount = "Azure Storage Account";
        private string _azureStorageKey = "Azure Storage Key";
        private string _azureStorageContainer = "Azure Storage Container";
        List<string> _copyState = null;
        private int _pendingCopiesCount;

        private void MockInitialize()
        {
            _awsS3Mock = new Mock<IAWSS3Facade>();
            _azureStorageBlobMock = new Mock<IAzureStorageBlobFacade>();
        }

        [TestInitialize]
        public void Initialize()
        {
            MockInitialize();
            _copyState = new List<string>();
            _pendingCopiesCount = 0;
        }


        [TestCleanup]
        public void Cleanup()
        {
            MockCleanup();
            _copyState = null;
        }

        private void MockCleanup()
        {
            _awsS3Mock = null;
            _azureStorageBlobMock = null;
        }

        private FileMigrator GetFileMigrator()
        {
            FileMigrator fileMigrator = new FileMigrator();
            fileMigrator.Initialize(_awsS3Bucket,
                _awsS3Account,
                _awsS3Key,
                _awsExpiryMinutes,
                _azureStorageAccount,
                _azureStorageKey,
                _azureStorageContainer,
                _awsS3Mock.Object,
                _azureStorageBlobMock.Object);

            return fileMigrator;
        }

        [TestMethod]
        public void IssuesConnectingWithAWSS3()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(false);

            FileMigrator fileMigrator = GetFileMigrator();
            string exceptionMessage = null;

            try
            {
                fileMigrator.MigrateFiles();
            }
            catch (Exception ex)
            {
                exceptionMessage = ex.Message;
            }

            Assert.IsTrue(exceptionMessage.Contains(Messages.AWSS3ConnectionIssues));
            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
        }

        [TestMethod]
        public void IssuesConnectingWithAzureStorageBlob()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(false);

            FileMigrator fileMigrator = GetFileMigrator();
            string exceptionMessage = null;

            try
            {
                fileMigrator.MigrateFiles();
            }
            catch (Exception ex)
            {
                exceptionMessage = ex.Message;
            }

            Assert.IsTrue(exceptionMessage.Contains(Messages.AzureStorageBlobConnectionIssues));
            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
        }

        [TestMethod]
        public void EmptyBucket()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _awsS3Mock.Setup(m => m.ListKeys())
                .Returns(new string[0]);

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(true);

            FileMigrator fileMigrator = GetFileMigrator();
            string exceptionMessage = null;

            try
            {
                fileMigrator.MigrateFiles();
            }
            catch (Exception ex)
            {
                exceptionMessage = ex.Message;
            }

            Assert.IsTrue(exceptionMessage.Contains(Messages.NoObjectsOnBucketWereFound));
            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
            _awsS3Mock.Verify(m => m.ListKeys(), Times.Once());
            _awsS3Mock.Verify(m => m.GenerateUrl(It.IsAny<string>()), Times.Never());
        }

        [TestMethod]
        public void NullBucket()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _awsS3Mock.Setup(m => m.ListKeys())
                .Returns<string[]>(null);

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(true);

            FileMigrator fileMigrator = GetFileMigrator();
            string exceptionMessage = null;

            try
            {
                fileMigrator.MigrateFiles();
            }
            catch (Exception ex)
            {
                exceptionMessage = ex.Message;
            }

            Assert.IsTrue(exceptionMessage.Contains(Messages.NoObjectsOnBucketWereFound));
            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
            _awsS3Mock.Verify(m => m.ListKeys(), Times.Once());
            _awsS3Mock.Verify(m => m.GenerateUrl(It.IsAny<string>()), Times.Never());
        }

        [TestMethod]
        public void CopyObjectsWithStartCopyExceptions()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _awsS3Mock.Setup(m => m.ListKeys())
                .Returns(new string[] {
                    "customer1/file1.txt",
                    "customer1/file2.txt",
                    "customer2/file1.txt",
                    "customer2/file2.txt",
                });

            _awsS3Mock.Setup(m => m.GenerateUrl(It.IsAny<string>()))
                .Returns((string key) => "https://bucket.s3-sa-east-1.amazonaws.com/" + key + "?AWSAccessKeyId=12345678901234567890&Expires=1234567890&Signature=1234567890123456789012345678901234");

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(true);

            _azureStorageBlobMock.SetupSequence(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()))
                .Returns("https://account.blob.core.windows.net/customer1/file1.txt")
                .Throws(new Exception("Something wrong has happended"));

            _azureStorageBlobMock.Setup(m => m.GetPendingCopies())
                .Returns(() => GetPendingCopiesNoFailures());

            FileMigrator fileMigrator = GetFileMigrator();
            fileMigrator.MigrateFiles();

            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
            _awsS3Mock.Verify(m => m.ListKeys(), Times.Once());
            _awsS3Mock.Verify(m => m.GenerateUrl(It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.GetPendingCopies(), Times.Exactly(3));
            _azureStorageBlobMock.Verify(m => m.RestartCopy(It.IsAny<string>()), Times.Never());
        }

        [TestMethod]
        public void CopyObjectsWithGetPendingCopiesExceptions()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _awsS3Mock.Setup(m => m.ListKeys())
                .Returns(new string[] {
                    "customer1/file1.txt",
                    "customer1/file2.txt",
                    "customer2/file1.txt",
                    "customer2/file2.txt",
                });

            _awsS3Mock.Setup(m => m.GenerateUrl(It.IsAny<string>()))
                .Returns((string key) => "https://bucket.s3-sa-east-1.amazonaws.com/" + key + "?AWSAccessKeyId=12345678901234567890&Expires=1234567890&Signature=1234567890123456789012345678901234");

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(true);

            _azureStorageBlobMock.Setup(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()))
                .Returns((string blobName, string sourceUrl) => "https://account.blob.core.windows.net/container/" + blobName);

            _azureStorageBlobMock.SetupSequence(m => m.GetPendingCopies())
                .Returns(GetPendingCopiesNoFailures())
                .Throws(new Exception("Something wrong has happended"));

            FileMigrator fileMigrator = GetFileMigrator();
            fileMigrator.MigrateFiles();

            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
            _awsS3Mock.Verify(m => m.ListKeys(), Times.Once());
            _awsS3Mock.Verify(m => m.GenerateUrl(It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.GetPendingCopies(), Times.Exactly(3));
            _azureStorageBlobMock.Verify(m => m.RestartCopy(It.IsAny<string>()), Times.Never());
        }

        [TestMethod]
        public void CopyObjectsNoFailures()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _awsS3Mock.Setup(m => m.ListKeys())
                .Returns(new string[] {
                    "customer1/file1.txt",
                    "customer1/file2.txt",
                    "customer2/file1.txt",
                    "customer2/file2.txt",
                });

            _awsS3Mock.Setup(m => m.GenerateUrl(It.IsAny<string>()))
                .Returns((string key) => "https://bucket.s3-sa-east-1.amazonaws.com/" + key + "?AWSAccessKeyId=12345678901234567890&Expires=1234567890&Signature=1234567890123456789012345678901234");

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(true);

            _azureStorageBlobMock.Setup(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()))
                .Returns((string blobName, string sourceUrl) => "https://account.blob.core.windows.net/container/" + blobName);

            _azureStorageBlobMock.Setup(m => m.GetPendingCopies())
                .Returns(() => GetPendingCopiesNoFailures());

            FileMigrator fileMigrator = GetFileMigrator();
            fileMigrator.MigrateFiles();

            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
            _awsS3Mock.Verify(m => m.ListKeys(), Times.Once());
            _awsS3Mock.Verify(m => m.GenerateUrl(It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.GetPendingCopies(), Times.Exactly(3));
            _azureStorageBlobMock.Verify(m => m.RestartCopy(It.IsAny<string>()), Times.Never());
        }

        private CopyState[] GetPendingCopiesNoFailures()
        {
            CopyState[] returnValue = null;

            if (_pendingCopiesCount == 0)
            {
                returnValue = new CopyState[] 
                { 
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer1/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer1/file2.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer2/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer2/file2.txt"
                    }
                };
            }
            else if (_pendingCopiesCount == 1)
            {
                returnValue = new CopyState[] 
                { 
                    new CopyState()
                    {
                        BytesCopied = 75,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer1/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 75,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer2/file2.txt"
                    }
                };
            }
            else
            {
                returnValue = new CopyState[0];
            }

            _pendingCopiesCount++;
            return returnValue;
        }

        [TestMethod]
        public void GenerateUrlWithException()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _awsS3Mock.Setup(m => m.ListKeys())
                .Returns(new string[] {
                    "customer1/fail1.txt",
                    "customer1/file2.txt",
                    "customer2/fail1.txt",
                    "customer2/file2.txt",
                    });

            _awsS3Mock.SetupSequence(m => m.GenerateUrl(It.IsAny<string>()))
                .Returns("https://bucket.s3-sa-east-1.amazonaws.com/customer1/file2.txt?AWSAccessKeyId=12345678901234567890&Expires=1234567890&Signature=1234567890123456789012345678901234")
                .Throws(new Exception("Something happened"));

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(true);

            _azureStorageBlobMock.Setup(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()))
                .Returns((string blobName, string sourceUrl) => "https://account.blob.core.windows.net/container/" + blobName);

            _azureStorageBlobMock.Setup(m => m.GetPendingCopies())
                .Returns(() => GetPendingCopiesWithFailures(_pendingCopiesCount))
                .Callback(() => _pendingCopiesCount++);

            FileMigrator fileMigrator = GetFileMigrator();
            fileMigrator.MigrateFiles();

            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
            _awsS3Mock.Verify(m => m.ListKeys(), Times.Once());
            _awsS3Mock.Verify(m => m.GenerateUrl(It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()), Times.AtMost(4));
            _azureStorageBlobMock.Verify(m => m.GetPendingCopies(), Times.AtMost(4));
            //_azureStorageBlobMock.Verify(m => m.RestartCopy(It.IsAny<string>()), Times.Exactly(2));
        }

        [TestMethod]
        public void CopyObjectsWithFailures()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _awsS3Mock.Setup(m => m.ListKeys())
                .Returns(new string[] {
                    "customer1/fail1.txt",
                    "customer1/file2.txt",
                    "customer2/fail1.txt",
                    "customer2/file2.txt",
                });

            _awsS3Mock.Setup(m => m.GenerateUrl(It.IsAny<string>()))
                .Returns((string key) => "https://bucket.s3-sa-east-1.amazonaws.com/" + key + "?AWSAccessKeyId=12345678901234567890&Expires=1234567890&Signature=1234567890123456789012345678901234");

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(true);

            _azureStorageBlobMock.Setup(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()))
                .Returns((string blobName, string sourceUrl) => "https://account.blob.core.windows.net/container/" + blobName);

            _azureStorageBlobMock.Setup(m => m.GetPendingCopies())
                .Returns(() => GetPendingCopiesWithFailures(_pendingCopiesCount))
                .Callback(() => _pendingCopiesCount++);

            FileMigrator fileMigrator = GetFileMigrator();
            fileMigrator.MigrateFiles();

            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
            _awsS3Mock.Verify(m => m.ListKeys(), Times.Once());
            _awsS3Mock.Verify(m => m.GenerateUrl(It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.GetPendingCopies(), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.RestartCopy(It.IsAny<string>()), Times.Exactly(2));
        }

        private CopyState[] GetPendingCopiesWithFailures(int pendingCopiesCount)
        {
            if (pendingCopiesCount == 0)
            {
                return new CopyState[] 
                { 
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer1/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer1/file2.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer2/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer2/file2.txt"
                    }
                };
            }
            else if (pendingCopiesCount == 1)
            {
                return new CopyState[] 
                { 
                    new CopyState()
                    {
                        BytesCopied = 75,
                        TotalBytes = 100,
                        Status = CopyStatus.Failed,
                        Url = "https://account.blob.core.windows.net/container/customer1/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 75,
                        TotalBytes = 100,
                        Status = CopyStatus.Failed,
                        Url = "https://account.blob.core.windows.net/container/customer2/file2.txt"
                    }
                };
            }
            else if (pendingCopiesCount == 2)
            {
                return new CopyState[] 
                { 
                    new CopyState()
                    {
                        BytesCopied = 75,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer1/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 75,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer2/file2.txt"
                    }
                };                
            }
            else
            {
                return new CopyState[0];
            }
        }

        [TestMethod]
        public void CopyObjectsWithInvalid()
        {
            _awsS3Mock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
                .Returns(true);

            _awsS3Mock.Setup(m => m.ListKeys())
                .Returns(new string[] {
                    "customer1/invalid1.txt",
                    "customer1/file2.txt",
                    "customer2/invalid1.txt",
                    "customer2/file2.txt",
                });

            _awsS3Mock.Setup(m => m.GenerateUrl(It.IsAny<string>()))
                .Returns((string key) => "https://bucket.s3-sa-east-1.amazonaws.com/" + key + "?AWSAccessKeyId=12345678901234567890&Expires=1234567890&Signature=1234567890123456789012345678901234");

            _azureStorageBlobMock.Setup(m => m.Initialize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
                .Returns(true);

            _azureStorageBlobMock.Setup(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()))
                .Returns((string blobName, string sourceUrl) => "https://account.blob.core.windows.net/container/" + blobName);

            _azureStorageBlobMock.Setup(m => m.GetPendingCopies())
                .Returns(() => GetPendingCopiesWithInvalid(_pendingCopiesCount))
                .Callback(() => _pendingCopiesCount++);

            FileMigrator fileMigrator = GetFileMigrator();
            fileMigrator.MigrateFiles();

            _awsS3Mock.Verify(m => m.Initialize(_awsS3Account, _awsS3Key, _awsS3Bucket, _awsExpiryMinutes), Times.Once());
            _azureStorageBlobMock.Verify(m => m.Initialize(_azureStorageAccount, _azureStorageKey, _azureStorageContainer), Times.Once());
            _awsS3Mock.Verify(m => m.ListKeys(), Times.Once());
            _awsS3Mock.Verify(m => m.GenerateUrl(It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.StartCopy(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(4));
            _azureStorageBlobMock.Verify(m => m.GetPendingCopies(), Times.Exactly(2));
            _azureStorageBlobMock.Verify(m => m.RestartCopy(It.IsAny<string>()), Times.Never());
        }

        private CopyState[] GetPendingCopiesWithInvalid(int pendingCopiesCount)
        {
            if (pendingCopiesCount == 0)
            {
                return new CopyState[] 
                { 
                    new CopyState()
                    {
                        BytesCopied = 0,
                        TotalBytes = 100,
                        Status = CopyStatus.Invalid,
                        Url = "https://account.blob.core.windows.net/container/customer1/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer1/file2.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 50,
                        TotalBytes = 100,
                        Status = CopyStatus.Pending,
                        Url = "https://account.blob.core.windows.net/container/customer2/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 0,
                        TotalBytes = 100,
                        Status = CopyStatus.Invalid,
                        Url = "https://account.blob.core.windows.net/container/customer2/file2.txt"
                    }
                };
            }
            else
            {
                return new CopyState[] 
                { 
                    new CopyState()
                    {
                        BytesCopied = 0,
                        TotalBytes = 100,
                        Status = CopyStatus.Invalid,
                        Url = "https://account.blob.core.windows.net/container/customer1/file1.txt"
                    },
                    new CopyState()
                    {
                        BytesCopied = 0,
                        TotalBytes = 100,
                        Status = CopyStatus.Invalid,
                        Url = "https://account.blob.core.windows.net/container/customer2/file2.txt"
                    }
                };
            }
        }
    }
}